package com.example.typhoonproject.controller;

import com.example.typhoonproject.common.utils.Util;
import com.example.typhoonproject.entity.TyphoonForecastEntity;
import com.example.typhoonproject.entity.TyphoonNmcCnEntity;
import com.example.typhoonproject.service.TyphoonForecastService;
import com.example.typhoonproject.service.TyphoonNmcCnService;
import com.example.typhoonproject.service.TyphoonPointService;
import com.example.typhoonproject.service.TyphoonService;
import com.slb.slnwp.common.utils.GlobalConstant;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 台风入口，并解析台风网实时和预测数据
 */
@Slf4j
@Component
public class TyphoonNmcCnTask {

    // 当天已经读取过的txt
    private final Set<String> readFiles = new HashSet<>();
    /*private Date lastTyphoonDataTime;
    private String lastTyphoonCode;*/
    private final Map<String, Date> typhoonDataTimes = new HashMap<>();
    @Autowired
    private TyphoonService typhoonService;
    @Autowired
    private TyphoonForecastService typhoonForecastService;
    @Autowired
    private TyphoonNmcCnService typhoonNmcCnService;
    @Value("${dataConfig.scriptPath}")
    private String scriptPath;
    @Value("${dataConfig.txtFilPath}")
    private String txtFilPath;
    @Autowired
    private TyphoonCsvTask typhoonCsvTask;
    private String lastCheckedDate;

    public static void main(String[] args) {
        //System.out.println("结果为==="+maps);

    }

    public void myTask() {
        // 创建线程池
        ScheduledExecutorService exec = Executors.newScheduledThreadPool(5);
        // 每隔1分钟读取一次的入库文件
        exec.scheduleWithFixedDelay(new Runnable() {
            public void run() {
                log.info("查询台风爬虫数据线程启动.....");
                try {
                    typhoonStart();
                } catch (Exception e) {
                    log.error("查询台风爬虫数据线程启动发生异常: {}", e.getMessage());
                }
            }
        }, 0, 1, TimeUnit.MINUTES);
    }

    private void typhoonStart() {
        // 1. 获取当前日期
        Date currentDate = new Date();

        // 格式化日期为 yyyyMMdd
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
        String formattedDate = dateFormat.format(currentDate);

        // 从格式化的日期中提取年和月（yyyyMM）和日（dd）
        String yearMonth = formattedDate.substring(0, 6);
        String day = formattedDate.substring(6, 8);
        log.info("当前运行时间========={}", formattedDate);

        // 检查日期是否变化
        if (lastCheckedDate == null || !lastCheckedDate.equals(formattedDate)) {
            // 如果日期变化，清空已读取文件的记录
            readFiles.clear();
            lastCheckedDate = formattedDate;
        }

        // 2. 读取指定路径文件夹
        String curPath = String.format("%s%s%s%s%s", txtFilPath, File.separator, yearMonth, File.separator, day);
        log.info("读取指定路径文件夹: {}", curPath);
        // 3. 解析目录中的所有txt文件并获取解析结果
        List<Map<String, Object>> parsedResults = parseTyphoonFiles(curPath);
        // 4. 如果有台风数据,调用Python脚本
        if (parsedResults != null && !parsedResults.isEmpty()) {
            for (Map<String, Object> parsedResultMap : parsedResults) {
                // 获取 实时 数据
                List<TyphoonNmcCnEntity> nmcResults = (List<TyphoonNmcCnEntity>) parsedResultMap.get("nmc");
                // 获取 预报 数据
                List<TyphoonForecastEntity> forecastResults = (List<TyphoonForecastEntity>) parsedResultMap.get("forecast");
                if (nmcResults != null && nmcResults.size() > 0) {
                    for (TyphoonNmcCnEntity result : nmcResults) {
                        // 5. 将当前台风设置为活跃
                        String typhoonCode = result.getCode();
                        // 将当前台风设置为活跃
                        typhoonService.updateStatus(typhoonCode, "active");
                        Date lastDataTime = typhoonDataTimes.get(typhoonCode);
                        // 如果台风代码不存在或数据时间较新
                        if (lastDataTime == null || new Date().after(lastDataTime)) {
                            log.info("调用台风数据========={}", result);
                            // 调用TyphoonCsvTask定时任务
                            typhoonCsvTask.myTask(typhoonCode);
                            // 调用python接口
                            callPythonScript(result);
                            // 更新最后一个台风数据的时间
                            typhoonDataTimes.put(typhoonCode, new Date());
                        }
                    }
                    // 6. 台风网实时数据入库
                    typhoonNmcCnService.saveBatch(nmcResults);
                }
                if (forecastResults != null && forecastResults.size() > 0) {
                    // 7. 台风网预报数据入库
                    typhoonForecastService.saveBatch(forecastResults);
                }

            }
        } else {
            long currentTime = new Date().getTime();
            // 比较台风是否超过12小时无数据
            typhoonDataTimes.entrySet().removeIf(entry -> {
                long lastDataTimeMillis = entry.getValue().getTime();
                if ((currentTime - lastDataTimeMillis) > TimeUnit.HOURS.toMillis(12)) {
                    log.info("超过12小时无台风数据，运行停止====={}", currentTime);
                    typhoonCsvTask.stopTask();
                    // 停止Python脚本
                    stopPythonScript(entry.getKey());
                    // 将台风变为不活跃
                    typhoonService.updateStatus(entry.getKey(), "no");
                    return true; // 返回 true 表示要移除该元素
                }
                return false; // 返回 false 表示不移除该元素
            });
        }
    }

    /**
     * 解析指定目录中的所有txt文件
     *
     * @param directoryPath 目录路径
     * @return 解析结果的列表
     */
    public List<Map<String, Object>> parseTyphoonFiles(String directoryPath) {
        // 解析txt结果
        List<Map<String, Object>> resultsLst = new ArrayList<>();
        File directory = new File(directoryPath);
        // 检查目录是否存在且不为空
        if (directory.exists() && directory.isDirectory()) {
            File[] txtFiles = directory.listFiles((dir, name) -> name.endsWith(".txt"));

            if (txtFiles != null && txtFiles.length > 0) {
                for (File file : txtFiles) {
                    // 如果文件已经读取过，则跳过
                    if (readFiles.contains(file.getName())) {
                        continue;
                    }
                    try {
                        log.info("当前解析的文件========={}", file.getName());
                        // 解析文件并将结果添加到列表中
                        resultsLst.add(parseFile(file));
                        // 记录已经读取过的文件
                        readFiles.add(file.getName());
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            } else {
                log.info("目录中没有找到txt文件。{}", directoryPath);
            }
        } else {
            log.info("目录不存在或为空。{}", directoryPath);
        }
        return resultsLst;
    }

    /**
     * 解析单个文件
     *
     * @param file 文件对象
     * @return 解析结果的列表
     * @throws IOException
     */
    public Map<String, Object> parseFile(File file) throws IOException {
        // 返回的实时和预报数据
        Map<String, Object> resultsMap = new LinkedHashMap<>();
        // 实时数据
        List<TyphoonNmcCnEntity> nmcResults = new ArrayList<>();
        // 预报数据
        List<TyphoonForecastEntity> forecastResults = new ArrayList<>();
        try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
            String line;
            String currentWindSpeed = null;
            int lineNumber = 0;

            TyphoonNmcCnEntity typhoonData = null;

            while ((line = reader.readLine()) != null) {
                // 检查当前行是否包含指定的关键词和台风编号
                if (containsTyphoonKeywords(line)) {
                    typhoonData = parseFirstLine(line, file.getName()); // 解析当前行并创建 TyphoonData 对象
                }
                if (line.contains("KTS WINDS")) {
                    // 当前风速行
                    currentWindSpeed = line.split("KTS")[0].trim();
                    continue;
                }
                if (currentWindSpeed != null && line.matches("\\d+KM\\s+(NORTHEAST|SOUTHEAST|SOUTHWEST|NORTHWEST)")) {
                    // 解析风向行
                    String[] parts = line.split("\\s+");
                    String distance = parts[0].split("KM")[0].trim(); // 提取距离
                    String direction = parts[1]; // 提取方向

                    // 将风速和风向数据保存到 TyphoonNmcCnEntity 中
                    String windLevel = GlobalConstant.WIND_LEVEL_MAP.get(currentWindSpeed);
                    if (windLevel != null) {
                        String key = windLevel + "_" + GlobalConstant.DIRECTION_MAP.get(direction);
                        double windSpeed = Double.parseDouble(distance); // 风速
                        switch (key) {
                            case "radius7_ne":
                                typhoonData.setRadius7_ne(windSpeed);
                                break;
                            case "radius7_se":
                                typhoonData.setRadius7_se(windSpeed);
                                break;
                            case "radius7_sw":
                                typhoonData.setRadius7_sw(windSpeed);
                                break;
                            case "radius7_nw":
                                typhoonData.setRadius7_nw(windSpeed);
                                break;
                            case "radius10_ne":
                                typhoonData.setRadius10_ne(windSpeed);
                                break;
                            case "radius10_se":
                                typhoonData.setRadius10_se(windSpeed);
                                break;
                            case "radius10_sw":
                                typhoonData.setRadius10_sw(windSpeed);
                                break;
                            case "radius10_nw":
                                typhoonData.setRadius10_nw(windSpeed);
                                break;
                            case "radius12_ne":
                                typhoonData.setRadius12_ne(windSpeed);
                                break;
                            case "radius12_se":
                                typhoonData.setRadius12_se(windSpeed);
                                break;
                            case "radius12_sw":
                                typhoonData.setRadius12_sw(windSpeed);
                                break;
                            case "radius12_nw":
                                typhoonData.setRadius12_nw(windSpeed);
                                break;
                        }
                    }
                    // 每4行处理一次风速类别
                    if (lineNumber % 4 == 3) {
                        // 重置当前风速
                        currentWindSpeed = null;
                    }
                    lineNumber++;
                } else if (line.contains("00HR")) {
                    parseSecondLine(line, typhoonData); // 解析下一行并填充 TyphoonData 对象

                } else if (line.startsWith("P+")) {
                    // 解析 P+ 行
                    TyphoonForecastEntity forEnty = parseForecastData(line, typhoonData.getCode(), typhoonData.getInitialTime());
                    if (forEnty != null) {
                        forecastResults.add(forEnty);
                    }
                } else if (line.startsWith("MOVE")) {
                    // 解析 MOVE 行
                    String[] parts = line.split("\\s+");
                    if (parts.length >= 3) {
                        String windDirection = parts[1]; // 获取风向（例如 WNW）
                        String moveSpeedStr = parts[2]; // 获取速度（例如 19KM/H）

                        // 去掉可能存在的 '=' 和 'KM/H' 后缀
                        moveSpeedStr = moveSpeedStr.replace("=", "").replace("KM/H", "").trim();

                        // 提取数字部分作为移动速度
                        double moveSpeed = 0;
                        try {
                            moveSpeed = Double.parseDouble(moveSpeedStr.replace("KM/H=", "").trim()); // 移除 "KM/H" 并转换为数字
                        } catch (NumberFormatException e) {
                            // 如果转换失败，使用默认值 0
                            moveSpeed = 0;
                        }

                        // 将解析结果存到 TyphoonData 对象
                        typhoonData.setWindDirection(windDirection); // 存储风向
                        typhoonData.setMoveSpeed(moveSpeed); // 存储移动速度
                    }
                }
            }
            if (typhoonData != null) {
                nmcResults.add(typhoonData); // 将解析后的数据添加到结果列表中
            }
            resultsMap.put("nmc", nmcResults);
            resultsMap.put("forecast", forecastResults);
        }
        return resultsMap;
    }

    /**
     * 检查行中是否包含指定的关键词和台风编号
     *
     * @param line 要检查的行
     * @return 如果包含关键词和编号则返回true，否则返回false
     */
    public boolean containsTyphoonKeywords(String line) {
        // 定义台风相关的关键词
        String[] keywords = {"TC", "TD", "TS", "STS", "TY", "STY", "SuperTY"};
        for (String keyword : keywords) {
            // 检查行中是否包含关键词，并且是否包含括号内的编号格式
            if (line.contains(keyword) && line.matches(".*\\(\\d+\\).*")) {
                return true;
            }
        }
        return false;
    }

    /**
     * 解析包含台风信息的第一行
     *
     * @param line 要解析的行
     * @return TyphoonData 对象
     */
    public TyphoonNmcCnEntity parseFirstLine(String line, String fileName) {
        TyphoonNmcCnEntity typhoonData = new TyphoonNmcCnEntity();
        String[] parts = line.split("\\s+");
        typhoonData.setIntensity(parts[0]);// 台风强度
        typhoonData.setEnName(parts[1]); // 获取台风英文名
        //typhoonData.setCode(parts[2].substring(1, parts[2].length() - 1)); // 获取台风编号，去掉括号
        String typhoonCode = "20" + parts[2];
        typhoonData.setCode(typhoonCode); // 获取台风编号
        // 从文件名中提取时间并转换为UTC
        String dateTimeString = fileName.substring(0, fileName.length() - 4);
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmm");
        LocalDateTime beijingTime = LocalDateTime.parse(dateTimeString, formatter);
        LocalDateTime utcTime = beijingTime.minusHours(8); // 北京时间转换为UTC时间

        // 获取YYYYMMDD部分
        String ymd = utcTime.format(DateTimeFormatter.ofPattern("yyyyMM"));

        // 获取DDHHmm部分
        String ddhhmm = parts[6];

        // 拼接完整的initialTime
        typhoonData.setInitialTime(ymd + ddhhmm);
        return typhoonData;
    }

    /**
     * 解析包含台风位置和强度的第二行
     *
     * @param line        要解析的行
     * @param typhoonData 要填充的 TyphoonData 对象
     */
    public void parseSecondLine(String line, TyphoonNmcCnEntity typhoonData) {
        String[] parts = line.split("\\s+");
        typhoonData.setLati(parseCoordinate(parts[1])); // 解析纬度
        typhoonData.setLoni(parseCoordinate(parts[2])); // 解析经度
        typhoonData.setEnpre(Double.parseDouble(parts[3].replace("HPA", "")) * 0.1); // 解析气压并转换单位
        typhoonData.setMaxwp(Double.parseDouble(parts[4].replace("M/S", "")) * 1.943); // 解析风速并转换单位
    }

    /**
     * 解析预报数据
     *
     * @param line
     * @param initialTime
     * @return
     */
    private TyphoonForecastEntity parseForecastData(String line, String code, String initialTime) {
        TyphoonForecastEntity entity = new TyphoonForecastEntity();
        entity.setCode(code);
        entity.setInitialTime(initialTime);
        // 处理最后一行可能以 "=" 结尾的情况
        if (line.endsWith("=")) {
            line = line.substring(0, line.length() - 1).trim(); // 去掉 "="
        }

        // 使用 split 方法解析 P+ 行
        String[] parts = line.split("\\s+");

        try {
            entity.setPTime(String.valueOf(Integer.parseInt(parts[0].substring(2, 4))));
            entity.setLati(Double.parseDouble(parts[1].substring(0, parts[1].length() - 1))); // 去掉 N/S
            entity.setLoni(Double.parseDouble(parts[2].substring(0, parts[2].length() - 1)));// 去掉 E/W
            entity.setEnpre(Double.parseDouble(parts[3].replace("HPA", "")));
            entity.setMaxwp(Double.parseDouble(parts[4].replace("M/S", ""))* 0.514);
            // 风速转台风强度
            entity.setIntensity(Util.getIntensity(Double.parseDouble(parts[4].replace("M/S", ""))* 0.514));
        } catch (NumberFormatException e) {
            System.out.println("解析数据时出错: " + e.getMessage());
            log.error("解析数据时出错:{}", e.getMessage());
        }

        System.out.println("新增预报数据: " + entity);
        log.info("新增预报数据: {}", entity);

        return entity;
    }

    /**
     * 解析经纬度坐标
     *
     * @param coordinate 要解析的坐标字符串
     * @return 解析后的坐标值
     */
    public double parseCoordinate(String coordinate) {
        double value = Double.parseDouble(coordinate.substring(0, coordinate.length() - 1));
        return coordinate.endsWith("S") || coordinate.endsWith("W") ? -value : value;
    }

    /**
     * 调用Python接口，生成scv文件
     *
     * @param entity
     */
    private void callPythonScript(TyphoonNmcCnEntity entity) {
        log.info("调用Python脚本生成scv文件。。。");
        String scripSh = scriptPath + "run_typhoon.sh";
        String command = String.format("sh %s start %s %s %s %s %s %s",
                scripSh,
                entity.getCode(),
                convertDateFormat(entity.getInitialTime()),
                entity.getLati(),
                entity.getLoni(),
                entity.getEnpre(),
                entity.getMaxwp()
        );

        log.info("调用Python的脚本command={}", command);
        try {
            ProcessBuilder processBuilder = new ProcessBuilder(command.split(" "));
            processBuilder.directory(new File(scriptPath));
            Process process = processBuilder.start();
            process.waitFor();
            log.info("Python脚本执行完成。");
        } catch (Exception e) {
            log.error("调用Python脚本时发生错误: {}", e.getMessage());
        }
    }

    /**
     * 将时间yyyyMMddHHmmss转换为Python调用需要的yyyyMMdd_HHmm
     *
     * @param initialTime
     * @return
     */
    private String convertDateFormat(String initialTime) {
        SimpleDateFormat inputFormat = new SimpleDateFormat("yyyyMMddHHmm");
        SimpleDateFormat outputFormat = new SimpleDateFormat("yyyyMMdd_HHmm");
        try {
            Date date = inputFormat.parse(initialTime);
            return outputFormat.format(date);
        } catch (ParseException e) {
            log.error("日期格式转换错误: {}", e.getMessage());
            return null;
        }
    }

    /**
     * 停止调用Python脚本
     */
    private void stopPythonScript(String code) {
        //String scriptPath = "/home/typhoon_system/run_typhoon.sh";
        String scripSh = scriptPath + "run_typhoon.sh";
        String command = String.format("sh %s stop %s",
                scripSh,
                code // 当前最新的台风编号code
        );

        try {
            ProcessBuilder processBuilder = new ProcessBuilder(command.split(" "));
            processBuilder.directory(new File(scriptPath));
            Process process = processBuilder.start();
            process.waitFor();
            log.info("停止Python脚本执行完成。");
        } catch (Exception e) {
            log.error("停止Python脚本时发生错误: {}", e.getMessage());
        }
    }
}
